<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <meta name="author" content="lijinbo" />
    <title>roller</title>
  </head>

  <body>
    <canvas id="myCanvas"></canvas>
    <div>
      <button id="start">开始</button>
      <button id="close">暂停</button>
    </div>
    <script>
      const W = document.documentElement.clientWidth
      const H = document.documentElement.clientHeight
      const cw = Math.floor(0.8 * W)
      const ch = Math.floor(0.8 * H)
      const rowMaxCount = Math.floor(cw / 21)

      class CreateRollerList {
        constructor() {
          this.docCount = 1
          this.addValue = 1
          this.docList = '😀,😁,😂,🤣,😃,😄,😅,😆,😉,😊,😋,😎,😍,😘,🥰,😗,👩,👨,🧑,👱,😖'.split(',')
          this.range = { min: 1, max: Math.floor(ch / 20) }
          this.chance = 0.7
        }
        // 创建每组图像
        createItemList() {
          let result = [],
            len = this.docList.length
          for (let i = 0; i < this.docCount; i++) {
            let item = i == this.docCount - 1 ? this.docList[~~(Math.random() * len)] : '||'
            result.push(item)
          }
          return result
        }
        // 数值增加边界判断
        judBoundary(val) {
          let temp = this.docCount + val
          if (temp > this.range.max) {
            return 0
          }
          if (temp < this.range.min) {
            return 0
          }
          return val
        }
        // 获取增加值
        getAddValue() {
          let val = 0
          if (Math.random() < this.chance) {
            val = Math.random() < 0.5 ? 1 : -1
          }
          return this.judBoundary(val)
        }
        // 创建数据
        create(count) {
          let list = []
          for (let i = 0; i < count; i++) {
            this.addValue = this.getAddValue()
            this.docCount += this.addValue
            let item = this.createItemList()
            list.push(item)
          }
          return list
        }
      }

      const roller = new CreateRollerList()
      let list = roller.create(rowMaxCount * 2)
      var c = document.getElementById('myCanvas')
      c.setAttribute('width', cw)
      c.setAttribute('height', ch)
      var ctx = c.getContext('2d')

      function clearCanvas() {
        ctx.clearRect(0, 0, cw, ch)
      }
      function renderPage(pageList) {
        clearCanvas()
        for (let i = 0; i < pageList.length; i++) {
          let rowItem = pageList[i]
          for (let j = 0; j < rowItem.length; j++) {
            let colItem = rowItem[j]
            ctx.font = '16px Arial'
            let x = 20 + i * 20
            let y = ch - (40 + j * 18)
            ctx.textAlign = 'center'
            ctx.fillText(colItem, x, y)
          }
        }
      }
      function sleep(t) {
        return new Promise((a) => setTimeout(a, t))
      }
      async function run() {
        let currentList = list.slice(0, rowMaxCount)
        renderPage(currentList)
        list.shift()
        list.push(...roller.create(1))
      }

      var start = document.getElementById('start')
      var close = document.getElementById('close')
      let sTime = null
      function clearTime() {
        clearInterval(sTime)
        sTime = null
      }
      function startCreate() {
        clearTime()
        sTime = setInterval(run, 50)
      }
      start.onclick = startCreate
      close.onclick = clearTime
      window.onload = function () {
        startCreate()
      }
    </script>
  </body>
</html>
